﻿#include "OpenGLSpecialEffectsWindow.h"
#include <QDebug>

#include <QFileDialog>
#include <QSize>
#include <QMessageBox>
#include "shader/dialog/ThresholdShaderDialog.h"
#include "shader/dialog/GammaShaderDialog.h"
#include "shader/dialog/NostalgiaShaderDialog.h"
#include "shader/dialog/BrightnessExposureContrastSaturationShaderDialog.h"
#include "shader/dialog/CtrlLShaderDialog.h"

extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
}

OpenGLSpecialEffectsWindow::OpenGLSpecialEffectsWindow(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	this->setWindowTitle("OpenGL特效项目");
	setAttribute(Qt::WA_DeleteOnClose, true);  // 关闭时自动销毁窗口
	timer = new QTimer();
	connect(timer, &QTimer::timeout, this, &OpenGLSpecialEffectsWindow::OnTimeout);
	timer->setInterval(40);//设置定时间隔
	timer->start();//启动定时器
}

void OpenGLSpecialEffectsWindow::setEffectsArgs(OpenGLEffects effect_type)
{
	switch (effect_type)
	{
	case OpenGLEffects::BLACK_AND_WHITE:
	{
		ThresholdShaderDialog dialog(this);
		connect(&dialog, &ThresholdShaderDialog::setThresholdValue, this, [this](float slideValue) {
			qDebug() << "---------------slideValue=>" << slideValue;
			ui.video->SetThresholdValue(slideValue);
			});
		dialog.exec();
	}
	break;
	case OpenGLEffects::GAMMA:
	{
		GammaShaderDialog gammaDialog(this);
		connect(&gammaDialog, &GammaShaderDialog::setGammaValue, this, [this](float gammaValue) {
			qDebug() << "---------------gammaValue=>" << gammaValue;
			ui.video->SetGammaValue(gammaValue);
			});
		gammaDialog.exec();
	}
	case OpenGLEffects::NOSTALGIA:
	{
		NostalgiaShaderDialog nostalgiaDialog(this);
		connect(&nostalgiaDialog, &NostalgiaShaderDialog::setNostalgiaValue, this, [this](float intensity, float grainAmount) {
			qDebug() << "---------------intensity=>" << intensity << "-----grainAmount=>" << grainAmount;
			ui.video->setNostalgiaValue(intensity, grainAmount);
			});
		nostalgiaDialog.exec();
	}
	break;
	case OpenGLEffects::BRIGHTNESS_EXPOSURE_CONTRAST_STURATION:
	{
		BrightnessExposureContrastSaturationShaderDialog dialog(this);
		connect(&dialog, &BrightnessExposureContrastSaturationShaderDialog::sendBrightnessExposureContrastSaturation,
			this, [this](float brightness, float exposure, float contrast, float saturation) {
				qDebug() << "---------------brightness=>" << brightness << "-----exposure=>" << exposure << "-----contrast=>" << contrast << "-----saturation=>" << saturation;
				ui.video->SetBrightnessExposureContrastSaturation(brightness, exposure, contrast, saturation);
			});
		dialog.exec();
	}
	break;
	case OpenGLEffects::CTRL_L:
	{
		CtrlLShaderDialog dialog(this);
		connect(&dialog, &CtrlLShaderDialog::SetCtrlArgs,
			this, [this](float shadow, float midtone, float highlight) {
				qDebug() << "---------------shadow=>" << shadow << "-----midtone=>" << midtone << "-----highlight=>" << highlight;
				ui.video->SetCtrlL(shadow, midtone, highlight);
			});
		dialog.exec();
	}
	break;
	}
}

void OpenGLSpecialEffectsWindow::onEffectsChanged(int pos)
{
	switch (pos)
	{
	case 0:
		ui.video->SetEffectsType(OpenGLEffects::ORIGINAL);
		break;
	case 1:
		ui.video->SetEffectsType(OpenGLEffects::GRAY);
		break;
	case 2:
		ui.video->SetEffectsType(OpenGLEffects::BLACK_AND_WHITE);
		setEffectsArgs(OpenGLEffects::BLACK_AND_WHITE);
		break;
	case 3:
		ui.video->SetEffectsType(OpenGLEffects::PIXEL_INVERSION);
		break;
	case 4:
		ui.video->SetEffectsType(OpenGLEffects::GAMMA);
		setEffectsArgs(OpenGLEffects::GAMMA);
		break;
	case 5:
		ui.video->SetEffectsType(OpenGLEffects::NOSTALGIA);
		setEffectsArgs(OpenGLEffects::NOSTALGIA);
		break;
	case 6:
		ui.video->SetEffectsType(OpenGLEffects::BRIGHTNESS_EXPOSURE_CONTRAST_STURATION);
		setEffectsArgs(OpenGLEffects::BRIGHTNESS_EXPOSURE_CONTRAST_STURATION);
		break;
	case 7:
		ui.video->SetEffectsType(OpenGLEffects::CTRL_L);
		setEffectsArgs(OpenGLEffects::CTRL_L);
		break;
	}
}


/// <summary>
/// C++ Qt + ffmpeg + openg渲染视频，总是频繁的崩溃。
///现已查明原因：OpenGL还没渲染完成TimeOut函数刷新就开始了。
///需要想一个办法让OpenGL渲染完成后再进行timeout，一帧一帧的来
/// 虽然找到了上述问题，但是又引申出了一个新的问题。ps：待调试解决
/// </summary>
void OpenGLSpecialEffectsWindow::OnTimeout()
{
	//qDebug() << "isDrawEnd()->" << ui.video->isDrawEnd();
	if (ui.video->isDrawEnd())
	{
		//qDebug() << "OnTimeout->Init";
		auto frame = frameList.Pop();
		if (frame)
		{
			//qDebug() << "OnTimeout->exec start";
			ui.video->Repaint(frame);
			/*int frame_ref_count = frame->buf[0] ? av_buffer_get_ref_count(frame->buf[0]) : 0;
			qDebug() << "AVFrame_Repaint的引用计数=>" << frame_ref_count;*/
			//qDebug() << "OnTimeout->exec end";
		}
	}
	else {
		//qDebug() << "OpenGL未绘制完成，等待中....";
	}

}

void OpenGLSpecialEffectsWindow::onSelectedFile()
{
	QString filter = "所有文件(*.*)"; //文件过滤器
	QString filePath = QFileDialog::getOpenFileName(this, "选择文件输出目录", "", filter);
	this->filePath = filePath;
	this->ui.outputPathEdit->setText(this->filePath);
}

void OpenGLSpecialEffectsWindow::onStartPlayVideo()
{

	if (this->filePath.isEmpty()) {
		QMessageBox::information(this, "温馨提示", "请选择视频文件");
		return;
	}
	//Release();
	isRunning = true;
	//connect(this, &OpenGLSpecialEffectsWindow::updateUi, this, &OpenGLSpecialEffectsWindow::OnUpdateUi, Qt::BlockingQueuedConnection);//QueuedConnection
	//封装/解封装器
	demuxer = new YDemuxer();
	//编码/解码器
	decoder = new YDecoder();

	///////////封装及解封装////////////////////
	auto ic = demuxer->Open(this->filePath.toStdString().c_str());
	demuxer->setContext(ic);
	int videoWidth = demuxer->GetVideoWidth();
	int videoHeight = demuxer->GetVideoHeight();

	ui.video->Init(videoWidth, videoHeight);

	///////////解码及编码////////////////////
	auto deContext = decoder->Create(demuxer->GetVideoCodecId(), false);
	decoder->setContext(deContext);
	//设置解码器参数
	demuxer->CopyParaParameters(demuxer->GetVideoIndex(), deContext);
	decoder->Open();

	renderThread = std::make_unique<std::thread>(&OpenGLSpecialEffectsWindow::OnStartPlay, this);
}
void OpenGLSpecialEffectsWindow::OnUpdateUi(AVFrame* frame)
{
	ui.video->Repaint(frame);
}

void OpenGLSpecialEffectsWindow::OnStartPlay()
{

	AVPacket pkt;
	auto frame = decoder->CreateFrame();
	while (isRunning)
	{
		if (!demuxer->Read(&pkt))break;
		if (pkt.stream_index == demuxer->GetVideoIndex())
		{

			if (decoder->Send(&pkt))
			{
				av_packet_unref(&pkt);
				while (decoder->Receive(frame))
				{

					while (frameList.Size() > 20)
					{
						MSleep(100);
						qDebug() << "空转-----------------------------";
						if (!isRunning) {
							break;
						}
						//continue;
					}

					auto f = av_frame_alloc();
					av_frame_ref(f, frame);//引用计数加1
					frameList.Push(f);
					av_frame_unref(frame);
					//qDebug() << "AVFrame已解码成功";
					/*int packet_ref_count = pkt.buf ? av_buffer_get_ref_count(pkt.buf) : 0;
					qDebug() << "AVPacket的引用计数=>" << packet_ref_count;*/

					/*int frame_ref_count = frame->buf[0] ? av_buffer_get_ref_count(frame->buf[0]) : 0;
					qDebug() << "AVFrame的引用计数=>" << frame_ref_count;*/

				}
				//qDebug() << "解码结束";
			}
		}
		else {
			av_packet_unref(&pkt);
			/*int packet_ref_count = pkt.buf ? av_buffer_get_ref_count(pkt.buf) : 0;
			qDebug() << "AVPacket_Audio的引用计数=>" << packet_ref_count;*/
		}
	}
	av_packet_unref(&pkt);
	/*int packet_ref_count = pkt.buf ? av_buffer_get_ref_count(pkt.buf) : 0;
	qDebug() << "AVPacket_Finish的引用计数=>" << packet_ref_count;*/
	if (frame)
	{
		/*int frame_ref_count = frame->buf[0] ? av_buffer_get_ref_count(frame->buf[0]) : 0;
		qDebug() << "AVFrame_Finish的引用计数=>" << frame_ref_count;*/
		av_frame_free(&frame);
	}

	qDebug() << "解封装结束";
}
void OpenGLSpecialEffectsWindow::Reset()
{

}
void OpenGLSpecialEffectsWindow::Release()
{
	if (isRunning)
	{
		isRunning = false;
		renderThread->join();
	}
	if (timer)
	{
		timer->stop();
		delete timer;
		timer = nullptr;
	}

	frameList.Clear();

	if (demuxer) {
		demuxer->Close();
		delete demuxer;
		demuxer = nullptr;
	}

	if (videoReScaler)
	{
		videoReScaler->Release();
		delete videoReScaler;
		videoReScaler = nullptr;
	}

	if (decoder)
	{
		decoder->Clear();
		std::vector<AVFrame*> frames = decoder->End();
		for (auto frame : frames)
		{
			av_frame_free(&frame);
			qDebug() << "释放缓冲区的AVFrame";
		}
		delete decoder;
		decoder = nullptr;
	}
}

void OpenGLSpecialEffectsWindow::closeEvent(QCloseEvent* event) {
	event->accept();  // 接受关闭事件（允许关闭）
	Release();
	qDebug() << "窗口已关闭";
}

OpenGLSpecialEffectsWindow::~OpenGLSpecialEffectsWindow()
{
	qDebug() << "窗口已销毁。。。。。。。";
}
